﻿/*
Copyright (c) 2010 Lance Ward
This software is licensed under the MIT license, except where otherwise noted.
For complete license details, refer to license.txt
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System.IO;
using ADNLib;

namespace ADNCanvas
{
    public class ToolAnimPointer : Tool
    {
        public ToolAnimPointer() { toolType = DrawingToolType.AnimPointer; }

		public override RectangleF EraseRect
		{
			get { return GetEraseRect(); }
		}

		private RectangleF GetEraseRect()
		{
			RectangleF rect;

			if (selObjects != null && selObjects.Count > 0 && mode != ToolMode.None)
			{
				Shape firstShape = (Shape)selObjects[0];
				rect = firstShape.Bounds;

				for (int i = 1; i < selObjects.Count; i++)
				{
					Shape s = (Shape)selObjects[i];
					rect = RectangleF.Union(rect, s.Bounds);
				}

				RectangleF prevRect = new RectangleF(prevPoint.X, prevPoint.Y, 0, 0);
                rect = RectangleF.Union(rect, prevRect);

				rect.Inflate(20, 20);
			}
			else if (currentShape != null) { rect = currentShape.Bounds; }
			else { rect = new RectangleF(); }

			return rect;
		}

		public override void MouseDown(PointF location, MouseButtons button, int clicks)
		{
			prevPoint = location;

			int index = HitTestObjects(location);
			bool isSelected = IsObjectSelected(index);

			if (index >= 0)
			{
				if (Control.ModifierKeys == Keys.Shift)
				{
					if (isSelected) { selObjects.Remove(xObjects[index]); }
					else { selObjects.Add(xObjects[index]); }
                    OnSelectionChanged();
				}
				else  //replace
				{
                    if (!isSelected)
                    {
                        selObjects.Clear();
                        selObjects.Add(xObjects[index]);
                        OnSelectionChanged();
                    }
                    else
                    {
                        //toggle selection mode
                        if (selMode == ToolSelectorMode.Rotate) { selMode = ToolSelectorMode.MoveSize; }
                        else if (selMode == ToolSelectorMode.MoveSize 
                            || selMode == ToolSelectorMode.None) 
                        { selMode = ToolSelectorMode.Rotate; }
                    }
				}
			}
			else
			{
				if (Control.ModifierKeys != Keys.Shift) { selObjects.Clear(); }
				else 
				{
                    selMode = ToolSelectorMode.None;
					mode = ToolMode.None;
					return;
				}
			}

			if (selObjects.Count > 0)
			{
				if (HitTestSelectors(location) >= 0)
				{
                    if (selMode == ToolSelectorMode.Rotate) { mode = ToolMode.Rotating; }
                    else { mode = ToolMode.Sizing; }
					return;
				}
				else
				{
					mode = ToolMode.Moving;
					return;
				}
			}
			else
			{
                selMode = ToolSelectorMode.None;
				mode = ToolMode.Boxing;
				currentShape = new ShapeSelect();
				currentShape.AppendPoint(location, false);
			}
		}

		public override void MouseMove(PointF location, MouseButtons button, int clicks)
		{

			switch (mode)
			{
				case ToolMode.None:
					{
						if (selObjects != null && selObjects.Count > 0)
						{
							int index = HitTestSelectors(location);
							if (index >= 0)
							{
                                string cursorPath = Path.Combine(Application.StartupPath, "rotate.cur");
                                if (selMode == ToolSelectorMode.Rotate) { OnCursorChange(new Cursor("rotate.cur")); }
                                else { OnCursorChange(GetCursor((SizeDirection)index)); }
							}
							else { OnCursorChange(Cursors.Default); }

							return;
						}
					}
					break;
				case ToolMode.Moving:
					{
						PointF p = new PointF(location.X - prevPoint.X, location.Y - prevPoint.Y);

						for (int i = 0; i < selObjects.Count; i++)
						{
							selObjects[i].Move(p);
							//prevPoint = location;
							OnRefresh(false);
						}
					}
					break;
				case ToolMode.Sizing:
					{
						PointF p = new PointF(location.X - prevPoint.X, location.Y - prevPoint.Y);

						for (int i = 0; i < selObjects.Count; i++)
						{
							selObjects[i].Resize(SizeDirection.East, p);
						}
					}
					break;
				case ToolMode.Rotating:
					{
                        if (selObjects != null && selObjects.Count > 0)
                        {
                            int index = HitTestSelectors(location);
                            if (index >= 0)
                            {
                                OnCursorChange(Cursors.Cross);
                            }
                            else { OnCursorChange(Cursors.Default); }

                            return;
                        }
					}
					break;
				case ToolMode.Boxing:
					{
						currentShape.AppendPoint(location, true);
					}
					break;
				default:
					break;

			}

			prevPoint = location;
		}

		public override void MouseUp(PointF location, MouseButtons button, int clicks)
		{
			if (mode == ToolMode.Boxing)
			{
				//add selected objects
				SelectObjects(currentShape.Bounds);
				currentShape = null;
                OnSelectionChanged();
			}

			OnRefresh(true);
			mode = ToolMode.None;
		}

		private bool IsObjectSelected(int index)
		{
			if (xObjects != null && selObjects != null && index >= 0)
			{
				for (int i = 0; i < selObjects.Count; i++)
				{
					if (xObjects[index] == selObjects[i])
					{
						return true;
					}
				}
			}

			return false;
		}

		private void SelectObjects(RectangleF r)
		{
			if (xObjects != null)
			{
				for (int i = xObjects.Count - 1; i >= 0; i--)
				{
					if (xObjects[i].HitTest(parentSurface, r))
					{
						selObjects.Add(xObjects[i]);
					}
				}
			}
		}

		private int HitTestSelectors(PointF p)
		{
			for (int i = 0; i < selObjects.Count; i++)
			{
				if (selObjects[i].Type == XObjectType.Shape)
				{
					Shape s = (Shape)selObjects[i];
                    int index = s.HitTestSelectors(parentSurface, p, selMode); 

					if (index >= 0) { return index; }
				}
			}

			return -1;
		}

		protected Cursor GetCursor(SizeDirection dir)
		{
			switch (dir)
			{
				case SizeDirection.NorthWest: return Cursors.SizeNWSE;
				case SizeDirection.North: return Cursors.SizeNS;
				case SizeDirection.NorthEast: return Cursors.SizeNESW;
				case SizeDirection.West: return Cursors.SizeWE;
				case SizeDirection.East: return Cursors.SizeWE;
				case SizeDirection.SouthWest: return Cursors.SizeNESW;
				case SizeDirection.South: return Cursors.SizeNS;
				case SizeDirection.SouthEast: return Cursors.SizeNWSE;
				default: return Cursors.SizeAll;
			}
		}
    }
}
